// import AutoLaunch from 'auto-launch'
import { app, BrowserWindow, ipcMain, shell } from 'electron'
import fs from 'fs'
import { createRequire } from 'node:module'
import os from 'node:os'
import path from 'node:path'
import { fileURLToPath } from 'node:url'

const require = createRequire(import.meta.url)
const __dirname = path.dirname(fileURLToPath(import.meta.url))

// The built directory structure
//
// ├─┬ dist-electron
// │ ├─┬ main
// │ │ └── index.js    > Electron-Main
// │ └─┬ preload
// │   └── index.mjs   > Preload-Scripts
// ├─┬ dist
// │ └── index.html    > Electron-Renderer
//
process.env.APP_ROOT = path.join(__dirname, '../..')

export const MAIN_DIST = path.join(process.env.APP_ROOT, 'dist-electron')
export const RENDERER_DIST = path.join(process.env.APP_ROOT, 'dist')
export const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL

process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL
  ? path.join(process.env.APP_ROOT, 'public')
  : RENDERER_DIST

// Disable GPU Acceleration for Windows 7
if (os.release().startsWith('6.1')) app.disableHardwareAcceleration()

// Set application name for Windows 10+ notifications
if (process.platform === 'win32') app.setAppUserModelId(app.getName())

if (!app.requestSingleInstanceLock()) {
  app.quit()
  process.exit(0)
}

let win: BrowserWindow | null = null
const preload = path.join(__dirname, '../preload/index.mjs')

// 动态获取正确的HTML路径
function getIndexHtmlPath() {
  if (app.isPackaged) {
    // 不使用asar打包时的路径
    const possiblePaths = [
      path.join(process.resourcesPath, 'app', 'dist', 'index.html'),
      path.join(__dirname, '../../dist/index.html'),
      path.join(app.getAppPath(), 'dist', 'index.html')
    ]
    
    for (const htmlPath of possiblePaths) {
      if (fs.existsSync(htmlPath)) {
        console.log('Found HTML at:', htmlPath)
        return htmlPath
      }
    }
    
    // 如果都找不到，使用默认路径
    console.log('Using fallback path:', possiblePaths[0])
    return possiblePaths[0]
  } else {
    // 开发环境路径
    return path.join(RENDERER_DIST, 'index.html')
  }
}

// 配置自动更新 - 使用try-catch包装
let autoUpdater: any = null
try {
  autoUpdater = require('electron-updater').autoUpdater
  autoUpdater.autoDownload = false
  autoUpdater.autoInstallOnAppQuit = true

  // 开发模式下强制检查更新
  if (process.env.NODE_ENV === 'development') {
    autoUpdater.forceDevUpdateConfig = true
    autoUpdater.updateConfigPath = path.join(process.cwd(), 'dev-app-update.yml')
  }
} catch (error) {
  console.log('electron-updater not available:', error.message)
}

async function createWindow() {
  win = new BrowserWindow({
    title: 'OT数字康复系统',
    icon: path.join(process.env.VITE_PUBLIC, 'logo.svg'),
    // 强制全屏，去掉窗口边框
    frame: false,
    fullscreen: true,
    // 设置窗口默认大小
    width: 1200,
    height: 800,
    // 允许用户调整窗口大小
    resizable: true,
    // 窗口居中显示
    center: true,
    webPreferences: {
      preload,
      webSecurity: false,
      allowRunningInsecureContent: true,
      experimentalFeatures: true,
      webviewTag: true, // 启用webview标签支持
      nodeIntegration: true, // 启用Node.js集成，webview需要
      contextIsolation: false, // 禁用上下文隔离，以便webview正常工作
      // Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
      // nodeIntegration: true,

      // Consider using contextBridge.exposeInMainWorld
      // Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
      // contextIsolation: false,
    },
  })

  // 隐藏菜单栏
  win.setMenuBarVisibility(false)

  if (VITE_DEV_SERVER_URL) { // #298
    win.loadURL(VITE_DEV_SERVER_URL)
    
  } else {
    // 使用动态路径函数
    const htmlPath = getIndexHtmlPath()
    win.loadFile(htmlPath)
  }

  // Test actively push message to the Electron-Renderer
  win.webContents.on('did-finish-load', () => {
    win?.webContents.send('main-process-message', new Date().toLocaleString())
  })

  // 修改CSP以允许unsafe-eval，用于vue-i18n
  win.webContents.session.webRequest.onHeadersReceived((details, callback) => {
    if (details.responseHeaders) {
      delete details.responseHeaders['content-security-policy']
      delete details.responseHeaders['Content-Security-Policy']
    }
    callback({ responseHeaders: details.responseHeaders })
  })

  // Make all links open with the browser, not with the application
  win.webContents.setWindowOpenHandler(({ url }) => {
    if (url.startsWith('https:')) shell.openExternal(url)
    return { action: 'deny' }
  })
  
  // F12 按键监听，打开调试窗口
  win.webContents.on('before-input-event', (event, input) => {
    if (input.key === 'F12') {
      if (win?.webContents.isDevToolsOpened()) {
        win.webContents.closeDevTools()
      } else {
        win?.webContents.openDevTools()
      }
    }
  })
  
  // win.webContents.on('will-navigate', (event, url) => { }) #344
}

app.whenReady().then(() => {
  createWindow()
  // 开机自启 - 使用try-catch包装
  try {
    const AutoLaunch = require('auto-launch')
    const myAppLauncher = new AutoLaunch({
      name: 'OT数字康复系统',
      path: app.getPath('exe'),
    })
    myAppLauncher.enable()
  } catch (error) {
    console.log('auto-launch not available:', error.message)
  }
})

app.on('window-all-closed', () => {
  win = null
  if (process.platform !== 'darwin') app.quit()
})

app.on('second-instance', () => {
  if (win) {
    // Focus on the main window if the user tried to open another
    if (win.isMinimized()) win.restore()
    win.focus()
  }
})

app.on('activate', () => {
  const allWindows = BrowserWindow.getAllWindows()
  if (allWindows.length) {
    allWindows[0].focus()
  } else {
    createWindow()
  }
})

// New window example arg: new windows url
ipcMain.handle('open-win', (_, arg) => {
  const childWindow = new BrowserWindow({
    webPreferences: {
      preload,
      nodeIntegration: true,
      contextIsolation: false,
      webviewTag: true, // 启用webview标签支持
      webSecurity: false,
      allowRunningInsecureContent: true,
    },
  })

  if (VITE_DEV_SERVER_URL) {
    childWindow.loadURL(`${VITE_DEV_SERVER_URL}#${arg}`)
  } else {
    childWindow.loadFile(getIndexHtmlPath(), { hash: arg })
  }
})

// 退出应用的 handler
ipcMain.handle('app-quit', () => {
  app.quit()
})

// 关机电脑的 handler
ipcMain.handle('shutdown-computer', () => {
  const { exec } = require('child_process')
  
  if (process.platform === 'win32') {
    // Windows 系统关机
    exec('shutdown /s /t 0', (error) => {
      if (error) {
        console.error('关机失败:', error)
      }
    })
  } else if (process.platform === 'darwin') {
    // macOS 系统关机
    exec('sudo shutdown -h now', (error) => {
      if (error) {
        console.error('关机失败:', error)
      }
    })
  } else {
    // Linux 系统关机
    exec('sudo shutdown -h now', (error) => {
      if (error) {
        console.error('关机失败:', error)
      }
    })
  }
})

// Windows 音量控制辅助函数
async function getWindowsVolume() {
  const { exec } = require('child_process')
  const util = require('util')
  const execAsync = util.promisify(exec)
  
  try {
    // 使用 Windows Core Audio API 获取音量
    const command = `powershell -Command "
      Add-Type @'
        using System;
        using System.Runtime.InteropServices;
        
        [Guid(\\"5CDF2C82-841E-4546-9722-0CF74078229A\\"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        interface IAudioEndpointVolume {
          int NotImpl1(); int NotImpl2(); int GetChannelCount(out int pnChannelCount);
          int SetMasterVolumeLevel(float fLevelDB, ref Guid pguidEventContext);
          int SetMasterVolumeLevelScalar(float fLevel, ref Guid pguidEventContext);
          int GetMasterVolumeLevel(out float pfLevelDB);
          int GetMasterVolumeLevelScalar(out float pfLevel);
        }
        
        [Guid(\\"D666063F-1587-4E43-81F1-B948E807363F\\"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        interface IMMDevice {
          int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, out IntPtr ppInterface);
        }
        
        [Guid(\\"A95664D2-9614-4F35-A746-DE8DB63617E6\\"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        interface IMMDeviceEnumerator {
          int NotImpl1();
          int GetDefaultAudioEndpoint(int dataFlow, int role, out IntPtr ppDevice);
        }
        
        [ComImport, Guid(\\"BCDE0395-E52F-467C-8E3D-C4579291692E\\")]
        class MMDeviceEnumeratorComObject { }
        
        public class VolumeHelper {
          [DllImport(\\"ole32.dll\\")]
          public static extern int CoCreateInstance(ref Guid rclsid, IntPtr pUnkOuter, uint dwClsContext, ref Guid riid, out IntPtr ppv);
          [DllImport(\\"ole32.dll\\")]
          public static extern int CoInitialize(IntPtr pvReserved);
          
          public static float GetMasterVolume() {
            CoInitialize(IntPtr.Zero);
            var deviceEnumeratorGuid = new Guid(\\"BCDE0395-E52F-467C-8E3D-C4579291692E\\");
            var deviceEnumeratorInterfaceGuid = new Guid(\\"A95664D2-9614-4F35-A746-DE8DB63617E6\\");
            var audioEndpointVolumeGuid = new Guid(\\"5CDF2C82-841E-4546-9722-0CF74078229A\\");
            
            IntPtr deviceEnumeratorPtr;
            CoCreateInstance(ref deviceEnumeratorGuid, IntPtr.Zero, 1, ref deviceEnumeratorInterfaceGuid, out deviceEnumeratorPtr);
            var deviceEnumerator = (IMMDeviceEnumerator)Marshal.GetObjectForIUnknown(deviceEnumeratorPtr);
            
            IntPtr devicePtr;
            deviceEnumerator.GetDefaultAudioEndpoint(0, 0, out devicePtr);
            var device = (IMMDevice)Marshal.GetObjectForIUnknown(devicePtr);
            
            IntPtr audioEndpointVolumePtr;
            device.Activate(ref audioEndpointVolumeGuid, 0, IntPtr.Zero, out audioEndpointVolumePtr);
            var audioEndpointVolume = (IAudioEndpointVolume)Marshal.GetObjectForIUnknown(audioEndpointVolumePtr);
            
            float volume;
            audioEndpointVolume.GetMasterVolumeLevelScalar(out volume);
            return volume;
          }
        }
'@
      try {
        $vol = [VolumeHelper]::GetMasterVolume()
        [Math]::Round($vol * 100)
      } catch {
        Write-Output '50'
      }
    "`
    
    const { stdout } = await execAsync(command)
    const volume = parseInt(stdout.trim())
    
    if (!isNaN(volume) && volume >= 0 && volume <= 100) {
      console.log('✅ 获取音量成功:', volume)
      return volume
    }
  } catch (error) {
    console.log('获取音量失败:', error.message)
  }
  
  return 50
}

async function setWindowsVolume(volumePercent) {
  const { exec } = require('child_process')
  const util = require('util')
  const execAsync = util.promisify(exec)
  const volumeScalar = volumePercent / 100
  
  try {
    // 使用 Windows Core Audio API 设置音量
    const command = `powershell -Command "
      Add-Type @'
        using System;
        using System.Runtime.InteropServices;
        
        [Guid(\\"5CDF2C82-841E-4546-9722-0CF74078229A\\"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        interface IAudioEndpointVolume {
          int NotImpl1(); int NotImpl2(); int GetChannelCount(out int pnChannelCount);
          int SetMasterVolumeLevel(float fLevelDB, ref Guid pguidEventContext);
          int SetMasterVolumeLevelScalar(float fLevel, ref Guid pguidEventContext);
          int GetMasterVolumeLevel(out float pfLevelDB);
          int GetMasterVolumeLevelScalar(out float pfLevel);
        }
        
        [Guid(\\"D666063F-1587-4E43-81F1-B948E807363F\\"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        interface IMMDevice {
          int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, out IntPtr ppInterface);
        }
        
        [Guid(\\"A95664D2-9614-4F35-A746-DE8DB63617E6\\"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        interface IMMDeviceEnumerator {
          int NotImpl1();
          int GetDefaultAudioEndpoint(int dataFlow, int role, out IntPtr ppDevice);
        }
        
        [ComImport, Guid(\\"BCDE0395-E52F-467C-8E3D-C4579291692E\\")]
        class MMDeviceEnumeratorComObject { }
        
        public class VolumeHelper {
          [DllImport(\\"ole32.dll\\")]
          public static extern int CoCreateInstance(ref Guid rclsid, IntPtr pUnkOuter, uint dwClsContext, ref Guid riid, out IntPtr ppv);
          [DllImport(\\"ole32.dll\\")]
          public static extern int CoInitialize(IntPtr pvReserved);
          
          public static bool SetMasterVolume(float volume) {
            try {
              CoInitialize(IntPtr.Zero);
              var deviceEnumeratorGuid = new Guid(\\"BCDE0395-E52F-467C-8E3D-C4579291692E\\");
              var deviceEnumeratorInterfaceGuid = new Guid(\\"A95664D2-9614-4F35-A746-DE8DB63617E6\\");
              var audioEndpointVolumeGuid = new Guid(\\"5CDF2C82-841E-4546-9722-0CF74078229A\\");
              
              IntPtr deviceEnumeratorPtr;
              CoCreateInstance(ref deviceEnumeratorGuid, IntPtr.Zero, 1, ref deviceEnumeratorInterfaceGuid, out deviceEnumeratorPtr);
              var deviceEnumerator = (IMMDeviceEnumerator)Marshal.GetObjectForIUnknown(deviceEnumeratorPtr);
              
              IntPtr devicePtr;
              deviceEnumerator.GetDefaultAudioEndpoint(0, 0, out devicePtr);
              var device = (IMMDevice)Marshal.GetObjectForIUnknown(devicePtr);
              
              IntPtr audioEndpointVolumePtr;
              device.Activate(ref audioEndpointVolumeGuid, 0, IntPtr.Zero, out audioEndpointVolumePtr);
              var audioEndpointVolume = (IAudioEndpointVolume)Marshal.GetObjectForIUnknown(audioEndpointVolumePtr);
              
              var guid = Guid.Empty;
              audioEndpointVolume.SetMasterVolumeLevelScalar(volume, ref guid);
              return true;
            } catch {
              return false;
            }
          }
        }
'@
      try {
        if ([VolumeHelper]::SetMasterVolume(${volumeScalar})) {
          Write-Output 'SUCCESS'
        } else {
          Write-Output 'FAILED'
        }
      } catch {
        Write-Output 'ERROR'
      }
    "`
    
    const { stdout } = await execAsync(command)
    if (stdout.trim() === 'SUCCESS') {
      console.log('✅ 设置音量成功:', volumePercent)
      return true
    } else {
      console.error('❌ 设置音量失败，输出:', stdout.trim())
      
      // 提供详细的错误诊断
      if (stdout.trim() === 'FAILED') {
        console.error('可能的原因:')
        console.error('- 权限不足，需要管理员权限')
        console.error('- 音频服务未运行')
        console.error('- 音频设备被其他程序占用')
        console.error('- 音频驱动异常')
        console.error('- COM组件初始化失败')
        console.error('- Windows系统未激活，可能影响系统功能')
      } else if (stdout.trim() === 'ERROR') {
        console.error('PowerShell执行错误，可能的原因:')
        console.error('- 系统权限不足')
        console.error('- PowerShell执行策略限制')
        console.error('- COM组件不可用')
        console.error('- Windows系统未激活，可能影响系统功能')
      }
      
      return false
    }
  } catch (error) {
    console.error('设置音量失败:', error.message)
    
    // 分析错误类型
    if (error.message.includes('permission') || error.message.includes('access')) {
      console.error('权限错误 - 需要管理员权限')
    } else if (error.message.includes('timeout')) {
      console.error('操作超时 - 音频服务可能无响应')
    } else if (error.message.includes('spawn')) {
      console.error('进程创建失败 - 系统资源不足')
    }
    
    return false
  }
}

// 音量控制 handler
ipcMain.handle('get-volume', async () => {
  console.log('🔊 开始获取系统音量...')
  
  // 优先尝试使用 loudness（开发和生产环境都尝试）
  try {
    const loudness = require('loudness')
    const volume = await loudness.getVolume()
    console.log('✅ 使用 loudness 获取音量:', volume)
    return volume
  } catch (e) {
    console.log('❌ loudness 不可用，使用 Windows API:', e.message)
  }
  
  // loudness 失败时使用 Windows API
  if (process.platform === 'win32') {
    const volume = await getWindowsVolume()
    return volume
  }
  
  return 50
})

ipcMain.handle('set-volume', async (_event, volume) => {
  const volumePercent = Math.max(0, Math.min(100, volume))
  console.log('🔊 开始设置系统音量:', volumePercent)
  
  // 优先尝试使用 loudness（开发和生产环境都尝试）
  try {
    const loudness = require('loudness')
    await loudness.setVolume(volumePercent)
    console.log('✅ 使用 loudness 设置音量:', volumePercent)
    return true
  } catch (e) {
    console.log('❌ loudness 不可用，使用 Windows API:', e.message)
  }
  
  // loudness 失败时使用 Windows API
  if (process.platform === 'win32') {
    const success = await setWindowsVolume(volumePercent)
    
    // 如果设置失败，提供详细错误信息
    if (!success) {
      console.error('❌ Windows API 设置音量失败')
      console.error('可能的原因:')
      console.error('1. 权限不足 - 需要管理员权限')
      console.error('2. 音频服务未运行 - 检查 Windows Audio 服务')
      console.error('3. 音频设备被占用 - 关闭其他音频程序')
      console.error('4. 音频驱动异常 - 重新插拔设备或更新驱动')
      console.error('5. COM组件异常 - 重启应用')
      console.error('6. Windows系统未激活 - 可能影响系统功能')
      console.error('   检查方法: 设置 > 更新和安全 > 激活')
    }
    
    return success
  }
  
  return false
})

ipcMain.handle('export-pdf', async (event, fileName = '训练报告.pdf') => {
  const win = BrowserWindow.fromWebContents(event.sender);
  if (!win) return;

  // 获取应用安装目录
  const appPath = app.getAppPath();
  const pdfDir = path.join(appPath, 'pdf');
  
  // 确保pdf目录存在
  if (!fs.existsSync(pdfDir)) {
    fs.mkdirSync(pdfDir, { recursive: true });
  }
  
  // 构建完整的文件路径
  const filePath = path.join(pdfDir, fileName);

  const pdfBuffer = await win.webContents.printToPDF({
    printBackground: true,
    pageSize: 'A4'
  });

  fs.writeFileSync(filePath, pdfBuffer);
  return filePath;
});

ipcMain.handle('save-image', async (event, fileName: string, arrayBuffer: ArrayBuffer, userFolderName: string) => {
  try {
    // 获取应用安装目录
    const appPath = app.getAppPath();
    const reportDir = path.join(appPath, 'report');
    
    // 确保report目录存在
    if (!fs.existsSync(reportDir)) {
      fs.mkdirSync(reportDir, { recursive: true });
    }
    
    // 创建用户专属文件夹：用户名-用户id
    const userDir = path.join(reportDir, userFolderName);
    if (!fs.existsSync(userDir)) {
      fs.mkdirSync(userDir, { recursive: true });
    }
    
    // 构建完整的文件路径
    const filePath = path.join(userDir, fileName);
    
    // 将arrayBuffer转换为Buffer并保存图片
    const buffer = Buffer.from(arrayBuffer);
    fs.writeFileSync(filePath, buffer);
    
    return filePath;
  } catch (error) {
    console.error('保存图片失败:', error);
    throw error;
  }
});

// 检查更新
ipcMain.handle('check-for-updates', async () => {
  if (!autoUpdater) {
    throw new Error('Auto updater not available')
  }
  try {
    const updateCheckResult = await autoUpdater.checkForUpdates()
    return {
      hasUpdate: !!updateCheckResult?.updateInfo,
      version: updateCheckResult?.updateInfo.version
    }
  } catch (error) {
    console.error('检查更新失败:', error)
    throw error
  }
})

// 下载更新
ipcMain.handle('download-update', async () => {
  if (!autoUpdater) {
    throw new Error('Auto updater not available')
  }
  try {
    await autoUpdater.downloadUpdate()
  } catch (error) {
    console.error('下载更新失败:', error)
    throw error
  }
})

// 监听下载进度
if (autoUpdater) {
  autoUpdater.on('download-progress', (progress) => {
    BrowserWindow.getAllWindows()[0]?.webContents.send('download-progress', progress)
  })

  // 监听下载完成
  autoUpdater.on('update-downloaded', () => {
    BrowserWindow.getAllWindows()[0]?.webContents.send('update-downloaded')
  })

  // 监听更新错误
  autoUpdater.on('error', (error) => {
    console.error('更新错误:', error)
    BrowserWindow.getAllWindows()[0]?.webContents.send('update-error', error)
  })
}
